#ifndef FIXED_ARRAY_H_
#define FIXED_ARRAY_H_

#include <array>
#include <cstring>

#include "ad_exception.h"
template <class T, std::uint32_t size>
class FixedArray {
 public:
  FixedArray() noexcept : number_{0U} {};
  ~FixedArray() = default;
  FixedArray(FixedArray const& fixedArray) noexcept {
    memcpy(data_array_.data(), fixedArray.data_array_.data(),
           fixedArray.number_ * sizeof(T));
    number_ = fixedArray.number_;
  }
  FixedArray& operator=(FixedArray const& fixedArray) noexcept {
    memcpy(data_array_.data(), fixedArray.data_array_.data(),
           fixedArray.number_ * sizeof(T));
    this->number_ = fixedArray.GetNumberFilled();
    return *this;
  }
  FixedArray(FixedArray&&) noexcept = delete;
  FixedArray& operator=(FixedArray&&) noexcept = delete;

  /// @brief Get member by index
  ///
  /// @param index  point index
  /// @throw AdException  when out of range
  ///@return member reference
  T const& Get(std::uint32_t index) const noexcept(false) {
    if (index >= number_) {
      throw AdException("member not exist");
    }
    return data_array_[index];
  }

  ///@brief get number filled
  ///@return number filled
  std::uint32_t GetNumberFilled() const noexcept { return number_; }

  /// @brief judge full
  /// @return if full return true, else false
  bool IsFull() {
    if (number_ == size) {
      return true;
    } else {
      return false;
    }
  }

  ///@brief add number
  ///@throw AdException number out of range
  void Add() noexcept(false) {
    if (number_ >= size) {
      throw AdException("number out of range");
    }
    number_++;
  }

  ///@brief get next member reference
  ///@return next member reference
  T& GetNext() noexcept { return data_array_[number_]; }

  ///@brief clear
  void Clear() noexcept { number_ = 0; }

 private:
  ///@brief data array
  std::array<T, size> data_array_;
  ///@brief number
  std::uint32_t number_;
};

#endif  // !FIXED_ARRAY_H_